﻿using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;

using Microsoft.Xna.Framework;

using System;
using System.Collections.Generic;
using System.Threading;






namespace FXnaEngine
{

    /// <summary>
    /// 主要用于一些公共变量的维护，方便调用，这个类只能在系统初始化之后使用
    /// </summary>
    internal static class FEngineState
    {




        static GraphicsDevice device;

        public static GraphicsDevice Device
        {
            get { return FEngineState.device; }
           
        }


        static GameServiceContainer services;


        public static GameServiceContainer Services
        {
          get { return FEngineState.services; }
         
        }


        static ContentManager content;

        public static ContentManager Content
        {
            get { return FEngineState.content; }
            
        }


        static IGraphicsDeviceService graphicsDeviceService;

        public static IGraphicsDeviceService GraphicsDeviceService
        {
            get { return FEngineState.graphicsDeviceService; }
           
        }




        #region Camera

        /// <summary>
        /// Matrices for shaders. Used in a similar way than in Rocket Commander,
        /// but since we don't have a fixed function pipeline here we just use
        /// these values in the shader. Make sure to set all matrices before
        /// calling a shader. Inside a shader you have to update the shader
        /// parameter too, just setting the WorldMatrix alone does not work.
        /// </summary>
        private static Matrix worldMatrix,
            viewMatrix,
            projectionMatrix;






        /// <summary>
        /// World matrix
        /// </summary>
        /// <returns>Matrix</returns>
        public static Matrix WorldMatrix
        {
            get
            {
                return worldMatrix;
            }
            set
            {
                worldMatrix = value;
                // Update worldViewProj here?
            }
        }

        /// <summary>
        /// View matrix
        /// </summary>
        /// <returns>Matrix</returns>
        public static Matrix ViewMatrix
        {
            get
            {
                return viewMatrix;
            }
            set
            {
                // Set view matrix, usually only done in ChaseCamera.Update!
                viewMatrix = value;

                // Update camera pos and rotation, used all over the game!
                invViewMatrix = Matrix.Invert(viewMatrix);
                camPos = invViewMatrix.Translation;
                cameraRotation = Vector3.TransformNormal(
                    new Vector3(0, 0, 1), invViewMatrix);
            }
        }

        /// <summary>
        /// Projection matrix
        /// </summary>
        /// <returns>Matrix</returns>
        public static Matrix ProjectionMatrix
        {
            get
            {
                return projectionMatrix;
            }
            set
            {
                projectionMatrix = value;
                // Update worldViewProj here?
            }
        }

        /// <summary>
        /// Camera pos, updated each frame in ViewMatrix!
        /// Public to allow easy access from everywhere, will be called a lot each
        /// frame, for example Model.Render uses this for distance checks.
        /// </summary>
        private static Vector3 camPos;

        /// <summary>
        /// Get camera position from inverse view matrix. Similar to method
        /// used in shader. Works only if ViewMatrix is correctly set.
        /// </summary>
        /// <returns>Vector 3</returns>
        public static Vector3 CameraPos
        {
            get
            {
                return camPos;
            }
        }

        /// <summary>
        /// Camera rotation, used to compare objects for visibility.
        /// </summary>
        private static Vector3 cameraRotation = new Vector3(0, 0, 1);

        /// <summary>
        /// Camera rotation
        /// </summary>
        /// <returns>Vector 3</returns>
        public static Vector3 CameraRotation
        {
            get
            {
                return cameraRotation;
            }
        }

        /// <summary>
        /// Remember inverse view matrix.
        /// </summary>
        private static Matrix invViewMatrix;

        /// <summary>
        /// Inverse view matrix
        /// </summary>
        /// <returns>Matrix</returns>
        public static Matrix InverseViewMatrix
        {
            get
            {
                return invViewMatrix;//Matrix.Invert(ViewMatrix);
            }
        }

        /// <summary>
        /// View projection matrix
        /// </summary>
        /// <returns>Matrix</returns>
        public static Matrix ViewProjectionMatrix
        {
            get
            {
                return ViewMatrix * ProjectionMatrix;
            }
        }

        /// <summary>
        /// World view projection matrix
        /// </summary>
        /// <returns>Matrix</returns>
        public static Matrix WorldViewProjectionMatrix
        {
            get
            {
                return WorldMatrix * ViewMatrix * ProjectionMatrix;
            }
        }
        #endregion



        #region 公共方法


        public static void InitEngine(IGraphicsDeviceService graphics, ContentManager content, GameServiceContainer services)
        {

            if (graphics == null || content == null)
                throw new Exception("graphics or content can not be null");

            FEngineState.services = services;

            graphicsDeviceService = graphics;

            device= graphics.GraphicsDevice;

            graphicsDeviceService.DeviceReset += new EventHandler<EventArgs>(graphicsDeviceService_DeviceReset);

         
            FEngineState.content = content;

 

        }

        static void graphicsDeviceService_DeviceReset(object sender, EventArgs e)
        {
            // Re-Set device
            device = graphicsDeviceService.GraphicsDevice;





            RestoreDeviceState();

        }



       


        public  static void RestoreDeviceState()
        {
            // Restore z buffer state
            device.DepthStencilState = DepthStencilState.Default;

            device.BlendState = BlendState.AlphaBlend;

            // Set u/v addressing back to wrap
            //_graphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;



        }




        #endregion


    }
}
